import * as THREE from 'three';
import { PathRecGeometry } from './PathRecGeometry';
import ResourceTracker from '@/editor/tools/ResourceTracker';
import { loadTexture } from '@/editor/tools/loader';

/**
 * 路径类
 */
export default class Road {
  /** 路径网格 */
  pathMesh: THREE.Mesh;

  /** 缓存用于绘制PathRec的配置项 */
  pathOption: Omit<Editor.PathRecGeometryOptions, 'path'>;

  /** 辅助路径网格 */
  supportMesh: THREE.Mesh;

  /** 路径点集合 */
  points: Array<THREE.Vector3> = [];

  /** 缓存用于绘制初始辅助路径的缓存点组 */
  firstCachePoints: Array<THREE.Vector3> = [];

  /** 材质 */
  material: THREE.MeshStandardMaterial;

  /** 是否正在进行变换 */
  isTransForming: boolean = false;

  /** 资源跟踪器，用于管理 THREE.js 对象的生命周期 */
  resourceTracker: ResourceTracker = null;

  /** 配置选项 */
  option: Editor.RoadOption;

  /** 路径高度 */
  yLevel: number;

  /**
   * 构造函数
   * @param option - 路径配置选项
   */
  constructor(option: Editor.RoadOption) {
    this.option = option;
    const { url, yLevel } = option;
    this.yLevel = yLevel;
    loadTexture(url).then((texture) => {
      this.material = new THREE.MeshStandardMaterial({
        map: texture,
        side: THREE.DoubleSide,
        roughness: 0.3,
        metalness: 0.2,
      });
    });
  }

  /**
   * 创建路径几何体
   * @param points - 路径点集合
   * @param pathOption - 路径配置选项(不传时使用默认配置)
   * @returns 创建的几何体
   */
  _createPathGeometry(points: Array<THREE.Vector3>, pathOption?: Omit<Editor.PathRecGeometryOptions, 'path'>): THREE.BufferGeometry {
    const path = new THREE.CatmullRomCurve3(points);
    path.curveType = 'catmullrom';
    path.tension = 0;
    // 合并参数，pathOption的优先级高
    const pathRecOption = Object.assign({ path, segments: 128, width: 20, height: 1 }, pathOption);
    const geometry = new PathRecGeometry(pathRecOption);
    this.pathOption = pathOption;
    return geometry;
  }

  /**
   * 更新路径
   * @param newPoint - 新的路径点
   * @param pathOption - 路径配置选项
   */
  update(newPoint: THREE.Vector3 | null, pathOption?: Omit<Editor.PathRecGeometryOptions, 'path'>): void {
    if (newPoint instanceof THREE.Vector3) {
      this.points.push(newPoint);
    }
    if (this.points.length < 2) return;
    // 贴图重复修正
    this.material.map.repeat.set(this.points.length * 5, 1);
    if (!this.pathMesh) {
      // 新增
      const { scene } = this.option;
      const newGeometry = this._createPathGeometry(this.points, pathOption);
      const pathMesh = new THREE.Mesh(newGeometry, this.material);
      // 资源跟踪
      this.resourceTracker = new ResourceTracker();
      this.resourceTracker.track(pathMesh);
      scene.add(pathMesh);
      this.pathMesh = pathMesh;
    } else {
      // 重绘更新
      this.pathMesh.geometry.dispose();
      this.pathMesh.geometry = this._createPathGeometry(this.points, pathOption);
    }
    this.pathOption = Object.assign({}, this.pathOption, pathOption);
  }

  /**
   * 闭合路径
   * @param closed - 是否闭合
   */
  close(closed: boolean = false): void {
    // 确保移除supportMesh
    this.removeSupportPath();
    // 闭合曲线
    if (closed) {
      const newPoint = this.points.length > 0 ? this.points[0] : new THREE.Vector3(0, this.yLevel, 0);
      this.update(newPoint, { closed });
    } else {
      // MARK: 这里必须要执行一次update，否则changeSize会在某些情况下显示异常
      this.update(null, { closed });
    }
  }

  /**
   * 更新缓存点
   * @param newPoint - 新的路径点
   */
  _updateCachePoints(newPoint: THREE.Vector3): void {
    if (typeof newPoint === 'undefined') return;
    const cacheLength = 4;
    if (this.firstCachePoints.length < cacheLength) {
      this.firstCachePoints.push(newPoint);
    } else {
      for (let i = 0; i < cacheLength; i++) {
        this.firstCachePoints[i] = this.firstCachePoints[i + 1];
      }
      this.firstCachePoints[cacheLength - 1] = newPoint;
    }
  }

  /**
   * 绘制辅助路径
   * @param mousePoints - 鼠标点集合
   * @param isFirst - 是否是首次绘制
   */
  createSupportPath(mousePoints: Array<THREE.Vector3>, isFirst: boolean = false): void {
    const { scene } = this.option;
    this.supportMesh && scene.remove(this.supportMesh);
    const points = this.points;
    // FIXME: 必须等material加载好，实际使用时存在异步问题
    if (points.length < 0 || !this.material) return;
    // 生成辅助路径,更新supportMesh
    if (!isFirst) {
      const newestPoint = points[points.length - 1];
      mousePoints.push(newestPoint);
    }
    // MARK:确保绘制路径的长度大于等于2
    if (mousePoints.length < 2) return;
    const geometry = this._createPathGeometry(mousePoints);
    const supportMesh = new THREE.Mesh(geometry, this.material);
    scene.add(supportMesh);
    this.supportMesh = supportMesh;
    // this.material.map.repeat.set(3, 1);
  }

  /**
   * 移除辅助路径
   */
  removeSupportPath(): void {
    const { scene } = this.option;
    this.supportMesh && scene.remove(this.supportMesh);
    this.supportMesh = null;
  }

  /**
   * 改变路面尺寸
   * @param sizeOption - 尺寸选项
   */
  changeSize(sizeOption: { width?: number; height?: number } = {}): void {
    const { width: currentWidth, height: currentHeight, closed } = this.pathOption;
    const { width, height } = sizeOption;
    if (currentHeight === height && currentWidth === width) return;
    // 更新配置项
    const newPathOption = Object.assign({}, this.pathOption, sizeOption);
    this.pathOption = newPathOption;
    this.update(null, newPathOption);
  }

  /**
   * 变换mesh的translate + rotate
   * @param controls - 控制器
   */
  changePosition(controls: Editor.Controls): void {
    this.isTransForming = !this.isTransForming;
    const { transformControls } = controls;
    if (this.isTransForming) {
      // 开启编辑
      controls.enableTransformModeMenu({
        initialMode: 'translate',
        visibleModes: [
          {
            mode: 'translate',
            callback: () => {
              transformControls.showX = true;
              transformControls.showZ = true;
              transformControls.showY = false;
            },
          },
          {
            mode: 'rotate',
            callback: () => {
              transformControls.showY = true;
              transformControls.showX = false;
              transformControls.showZ = false;
            },
          },
        ],
      });
      transformControls.enabled = true;
      transformControls.attach(this.pathMesh);
    } else {
      // 关闭编辑
      controls.detachTransfromControls();
    }
  }

  /**
   * 改变路面贴图
   * @param url - 贴图URL
   */
  async changeTexture(url: string): Promise<void> {
    try {
      const texture = await loadTexture(url);
      // 使用clone避免repeat设置丢失
      const currentRepeat = this.material.map?.repeat?.clone() || new THREE.Vector2(1, 1);
      this.material.map = texture;

      // 恢复并更新repeat设置
      texture.repeat.copy(currentRepeat);
      texture.repeat.x = this.points.length * 5;

      texture.needsUpdate = true;
      this.material.needsUpdate = true;
    } catch (error) {
      console.error('[Road-changeTexture]' + error);
    }
  }

  /**
   * 获取路径信息
   * @returns 路径信息
   */
  getInfo(): { pathOption: Omit<Editor.PathRecGeometryOptions, 'path'>; points: Array<THREE.Vector3> } {
    return { pathOption: this.pathOption, points: this.points };
  }

  destroy(): void {
    const { scene } = this.option;
    this.pathMesh && scene.remove(this.pathMesh);
    this.resourceTracker.dispose();
    this.supportMesh && scene.remove(this.supportMesh);
    this.resourceTracker = null;
    this.pathMesh = null;
    this.supportMesh = null;
    this.material = null;
    this.points = [];
  }
}
